#ifndef VISCOMPONENT_H
#define VISCOMPONENT_H

#pragma once

#include <stack>
#include <vector>

#include <LDF/CompositeNode.h>
#include <LDF/VisComponentState.h>
#include <LDF/VisComponentStrategy.h>
#include <LDF/IBufferProxy.h>

// Forward declarations to avoid including classes that only the name is needed in here
class Point3f;
class LargeDisplayManager;
class LargeDisplayEvent;


/**
 * This class implements a visualization component of the Large Dispaly
 * Framework. It is a node in a composite pattern, which allows components
 * to be composed of other components and to be treated uniformly. A component
 * has a set of i-buffers that can be accessed by other components (usually,
 * its composite children) and can access data in the i-buffers of other
 * components (usually, composite ancestors). The state of a component is
 * encapsulated in a VisComponentState object that can be stacked inside the
 * component itself for saving and retrieving states.
 *
 * A specialized component is defined by adding one or more behavior
 * strategies, instead of subclassing. The component's i-buffers should also be
 * specified throught the associated strategies. To set a component's strategy,
 * a VisComponentStrategy object should be specified and pushed into the
 * component object's chain of strategies. This defines how the component
 * should draw itself and behave during interaction.
 *
 * Animation of the component can be defined by using the source and target
 * states (both are VisComponentState objects). The states are linearly
 * interpolated during the component rendering by updating the animation
 * parameter in accord with the current value of the animation step.
 *
 * This class was refactored from the original VisComponent class written by
 * Andre Miede and Tobias Isenberg in the Interactions Lab at the University of
 * Calgary, Canada.
 *
 * @author Fabricio Anastacio - fabriciocfa@yahoo.com
 * @since June 25, 2007
 */
class LARGEDISPLAYFRAMEWORKLAYER_API VisComponent : public CompositeNode
{
	// Constants
public:
	// Identifiers for the attributes that should be kept in state retrieval

	/** In retrieving a state, no attribute should be kept (retrieve everything). */
	const static unsigned int NONE = 0;

	/** In retrieving a state, keep the position. */
	const static unsigned int POSITION = 1;

	/** In retrieving a state, keep the rotation angle. */
	const static unsigned int ROTATION_ANGLE = 2;

	/** In retrieving a state, keep the width. */
	const static unsigned int WIDTH = 4;

	/** In retrieving a state, keep the height. */
	const static unsigned int HEIGHT = 8;

	/** In retrieving a state, keep the x-coordinate scale factor. */
	const static unsigned int SCALE_FACTOR_X = 16;

	/** In retrieving a state, keep the y-coordinate scale factor. */
	const static unsigned int SCALE_FACTOR_Y = 32;

	/** In retrieving a state, keep the z-coordinate scale factor. */
	const static unsigned int SCALE_FACTOR_Z = 64;

	/** In retrieving a state, keep the red component of its color. */
	const static unsigned int COLOR_RED = 128;

	/** In retrieving a state, keep the green component of its color. */
	const static unsigned int COLOR_GREEN = 256;

	/** In retrieving a state, keep the blue component of its color. */
	const static unsigned int COLOR_BLUE = 512;

	/** In retrieving a state, keep the alpha component of its color. */
	const static unsigned int COLOR_ALPHA = 1028;


	// Attributes
protected:

	/** The unique identifier of this component. */
	unsigned long id;

	/** The color identifier derived from this component id. */
	unsigned char idColor[3];


	/** The manager that owns this component. */
	LargeDisplayManager* manager;

	// STATE HANDLING

	/** The current state of this  commponent. */
	VisComponentState currentState;

	/** The stack that holds previous/alternative states of this component. */
	std::stack<VisComponentState> stateStack;

	// I-BUFFERS

	/**
	 * The collection of active i-Buffers held by this component. This
	 * collection is indexed by unsigned int values defined by the
	 * VisComponentStrategy object associated with this component. This same
	 * object is also responsible for creating the IBuffer objects added to
	 * this collection. A component is suppposed to have the same elements in
	 * this collection throughout its lifetime. Therefore, performance of
	 * insertions and deletions on this collection is not crucial. The most
	 * significant aspect is the performance of finding elements for readings
	 * and updates. Thus, this operation must be carried out in constant time
	 * (O(1)).
	 */
	std::vector<IBufferProxy*> activeBuffers;
//	std::map<unsigned int, IBuffer*> properties;
//	HASH_MAP_EXTENSION::hash_map<unsigned int, IBuffer*> properties;

	/**
	 * The collection of references to the passive i-buffers used by this
	 * component. This collection is indexed by unsigned int values defined by
	 * the VisComponentStrategy object associated with this component. This
	 * same object is also responsible for creating the IBufferProxy objects
	 * added to this collection. A component is suppposed to have the same
	 * elements in this collection throughout its lifetime (although they might
	 * be empty). Therefore, performance of insertions and deletions on this
	 * collection is not crucial. The most significant aspect is the
	 * performance of finding elements for readings and updates. Thus, this
	 * operation must be carried out in constant time (O(1)). The references in
	 * this collection must be updated everytime the path from this component
	 * to the root component of its composite structure changes. If no
	 * component in the path to root has an active buffer of the same type as a
	 * given passive buffer request, the reference inside the IBufferProxy
	 * object is set to NULL.
	 */
	std::vector<IBufferProxy*> passiveBuffers;


	/** The strategy being used for this component. */
	VisComponentStrategy* strategy;

	// ANIMATION

	/** The size of the linear step used for animation with linear interpolation (between 0 and 1). */
	float animationStep;

	/** The current value used to parameterize animation (between 0 and 1). */
	float animationParameter;

	/** If true, indicates that an animation is running. */
	bool animating;

	/** The state where the animation starts. */
	VisComponentState sourceState;

	/** The state where the animation stops. */
	VisComponentState targetState;

	/** The exception attributes for the animation triggered when this
	 * component is removed from a container. */
	unsigned int removingInvariants;


	// Methods
public:

	/**
	 * Constructs a component.
	 */
	VisComponent(void);

	/**
	 * Destroys this component.
	 */
	virtual ~VisComponent(void);

	// RENDERING

	/**
	 * Renders this component.
	 *
	 * @param selectedIds the list of currently selected ids.
	 * @param enablePicking if true, draw for selection mode (adding the
	 * component id).
	 * @param containerOnly if true, only renders this component if it is a
	 * container (i. e., not a leaf).
	 */
	void render(const std::vector<unsigned long>& selectedIds,
		bool enablePicking, bool containerOnly = false);

	/**
	 * Renders the composite children of this component.
	 *
	 * @param selectedIds the list of currently selected ids.
	 * @param enablePicking if true, draw for selection mode (adding the
	 * component id).
	 * @param containerOnly if true, only renders this component if it is a
	 * container (i. e., not a leaf).
	 */
	void renderChildren(const std::vector<unsigned long>& selectedIds,
		bool enablePicking, bool containerOnly = false);

	/**
	 * Renders this component and all its children, which in turn render their
	 * children, and so on.
	 *
	 * @param selectedIds the list of currently selected ids.
	 * @param enablePicking if true, draw for selection mode (adding the
	 * component id).
	 * @param containerOnly if true, only renders this component if it is a
	 * container (i. e., not a leaf).
	 */
	void renderBranch(const std::vector<unsigned long>& selectedIds,
		bool enablePicking, bool containerOnly = false);

	/**
	 * Renders this component and all its children, which in turn render their
	 * children, and so on, except if this component has the specified id.
	 *
	 * @param selectedIds the list of currently selected ids.
	 * @param enablePicking if true, draw for selection mode (adding the
	 * component id).
	 * @param containerOnly if true, only renders this component if it is a
	 * container (i. e., not a leaf).
	 * @param exceptionId the id of the component that should not be rendered.
	 */
	void renderBranchWithException(const std::vector<unsigned long>& selectedIds,
		bool enablePicking, bool containerOnly, unsigned long exceptionId);

	/**
	 * Renders this component and all its children, which in turn render their
	 * children, and so on, except if the id of this component is in the list
	 * of exceptions.
	 *
	 * @param selectedIds the list of currently selected ids.
	 * @param enablePicking if true, draw for selection mode (adding the
	 * component id).
	 * @param containerOnly if true, only renders this component if it is a
	 * container (i. e., not a leaf).
	 * @param exceptionIds the list of the ids of the components that should
	 * not be rendered.
	 */
	void renderBranchWithException(const std::vector<unsigned long>& selectedIds,
		bool enablePicking, bool containerOnly, const std::vector<unsigned long>& exceptionId);

	// ANIMATION

	/**
	 * Starts an animation.
	 */
	void startAnimation();

	/**
	 * Stops an animation.
	 */
	void stopAnimation();

	/**
	 * Determines what to do at the given animation step. The default behavior
	 * is to interpolate the source and target states of this component.
	 *
	 * @param t the interpolation parameter used to calculate the animation. It
	 * should be between 0.0 and 1.0.
	 */
	virtual void animate(float t);

	/**
	 * Animates this component when it is removed from a container. The
	 * animation is done by retrieving the state currently on top of this
	 * component's stack and setting it as the animation's target state. The
	 * current state is set as the animation's source state. After the source
	 * and target states are properly set, the animation is triggered to start.
	 * The attributes specified as invariants are maintained during the
	 * process. This function should be called by a strategy whenever this
	 * behavior is required.
	 *
	 * @param invariants the bitwise OR combination of the constants that
	 * identify which attributes should not be retrieved from the previously
	 * saved state.
	 */
	void animateRemoving(unsigned int invariants);

	/**
	 * Animates this component when it is added to a container. If buffer
	 * reading is required in order to update the component when inside the
	 * container, this is specified by the parameter 'types'. This parameter is
	 * forwarded to the readPassiveBuffers() function in this component's
	 * strategy in order to have specific actions carried out. If the state
	 * stack is empty, this method saves the current state of this component,
	 * sets it as the animation's source, and sets the target state as the
	 * current state modified by the the specified buffer reading. If there is
	 * a state already in the stack, the animation's target is set as this top
	 * state altered by reading the specified buffer(s). The attributes
	 * specified as invariants are maintained during the process. This function
	 * should be called by a strategy whenever this behavior is required.
	 *
	 * @param types the types of buffers that should be read from the container.
	 * @param invariants the bitwise OR combination of the constants that
	 * identify which attributes should not be retrieved from the previously
	 * saved state.
	 */
	void animateAdding(const std::vector<unsigned int>& types, unsigned int invariants);

	// EVENT HANDLING (STRATEGY FORWARDING)

	/**
	 * Handles the given event.
	 *
	 * @param evt the event to be handled.
	 */
	inline void onEvent(LargeDisplayEvent* evt) { if (strategy) strategy->onEventComponent(evt); }

	/**
	 * Defines what happens when the component is resized. Due to the use of
	 * templates for representing the i-buffers, the component's strategy
	 * should resize all the active buffers of the associated component.
	 *
	 * @param width the new width of the component.
	 * @param height the new height of the component.
	 */
	inline virtual void resize(unsigned int width, unsigned int height) {
		setWidth(width); setHeight(height);
		if (strategy) strategy->resizeComponent(width, height);
	}

	/**
	 * Defines what happens when the component is dropped insed another
	 * component/container.
	 *
	 * @param parentChanged true if the component's parent changed with the
	 * dropping.
	 */
	inline virtual void drop(bool parentChanged) { bool added = false;
		if (strategy) added = strategy->dropComponent(parentChanged);
		if (!added && parentChanged) animateRemoving(removingInvariants);
	}

	// COORDINATE CONVERSIONS

	/**
	 * Converts the given global coordinates (with origin in the bottom left
	 * corner of the screen) to this component buffer coordinate frame (with
	 * origin in the bottom left corner of this component bounding rectangle,
	 * given by its width, height, center/position, and up-vector direction).
	 *
	 * @param globalX the global x-coordinate
	 * @param globalY the global y-coordinate
	 * @param bufferX the calculated x-coordinate in the component buffer frame
	 * @param bufferY the calculated y-coordinate in the component buffer frame
	 */
	void convertGlobalToBufferCoords(double globalX, double globalY,
		double& bufferX, double& bufferY);

	/**
	 * Converts the given global coordinates (with origin in the bottom left
	 * corner of the screen) to this component buffer coordinate frame (with
	 * origin in the bottom left corner of this component bounding rectangle,
	 * given by its width, height, center/position, and up-vector direction).
	 * OBS.: The conversion is only done for the x and y coordinates. The z
	 * coordinate is ignored.
	 *
	 * @param global the global coordinates to be converted
	 * @param buffer the calculated coordinates in the component buffer frame
	 */
	void convertGlobalToBufferCoords(const Point3f& global, Point3f& buffer);

	/**
	 * Converts the given coordinates in this component buffer frame (with
	 * origin in the bottom left corner of this component bounding rectangle,
	 * given by its width, height, center/position, and up-vector direction) to
	 * global coordinates (with origin in the bottom left corner of the screen).
	 *
	 * @param bufferX the x-coordinate in the component buffer frame
	 * @param bufferY the y-coordinate in the component buffer frame
	 * @param globalX the calculated global x-coordinate
	 * @param globalY the calculated global y-coordinate
	 */
	void convertBufferToGlobalCoords(double bufferX, double bufferY,
		double& globalX, double& globalY);

	/**
	 * Converts the given coordinates in this component buffer frame (with
	 * origin in the bottom left corner of this component bounding rectangle,
	 * given by its width, height, center/position, and up-vector direction) to
	 * global coordinates (with origin in the bottom left corner of the screen).
	 * OBS.: The conversion is only done for the x and y coordinates. The z
	 * coordinate is ignored.
	 *
	 * @param buffer the coordinates in the component buffer frame
	 * @param global the calculated global coordinates
	 */
	void convertBufferToGlobalCoords(const Point3f& buffer, Point3f& global);


	/**
	 * Converts the current position of this component to its parent's buffer
	 * coordinate frame (if it has a parent).
	 *
	 * @param parentX the x-coordinate in the parent frame
	 * @param parentY the y-coordinate in the parent frame
	 */
	void convertPositionToParentBufferCoords(double& parentX, double& parentY);


	/**
	 * Converts the given global coordinates (with origin in the bottom left
	 * corner of the screen) to this component coordinate frame (with origin in
	 * the center of this component bounding rectangle, given by its width,
	 * height, center/position, and rotation angle).
	 *
	 * @param globalX the global x-coordinate
	 * @param globalY the global y-coordinate
	 * @param componentX the calculated x-coordinate in the component frame
	 * @param componentY the calculated y-coordinate in the component frame
	 */
	void convertGlobalToComponentCoords(double globalX, double globalY,
		double& componentX, double& componentY);

	/**
	 * Converts the given global coordinates (with origin in the bottom left
	 * corner of the screen) to this component coordinate frame (with origin in
	 * the center of this component bounding rectangle, given by its width,
	 * height, center/position, and rotation angle).
	 * OBS.: The conversion is only done for the x and y coordinates. The z
	 * coordinate is ignored.
	 *
	 * @param global the global coordinates to be converted
	 * @param component the calculated coordinates in the component frame
	 */
	void convertGlobalToComponentCoords(const Point3f& global, Point3f& component);

	/**
	 * Converts the given coordinates in this component frame (with origin in
	 * the center of this component bounding rectangle, given by its width,
	 * height, center/position, and rotation angle) to global coordinates (with
	 * origin in the bottom left corner of the screen).
	 *
	 * @param componentX the x-coordinate in the component frame
	 * @param componentY the y-coordinate in the component frame
	 * @param globalX the calculated global x-coordinate
	 * @param globalY the calculated global y-coordinate
	 */
	void convertComponentToGlobalCoords(double componentX, double componentY,
		double& globalX, double& globalY);

	/**
	 * Converts the given coordinates in this component frame (with origin in
	 * the center of this component bounding rectangle, given by its width,
	 * height, center/position, and rotation angle) to global coordinates (with
	 * origin in the bottom left corner of the screen).
	 * OBS.: The conversion is only done for the x and y coordinates. The z
	 * coordinate is ignored.
	 *
	 * @param component the coordinates in the component buffer frame
	 * @param global the calculated global coordinates
	 */
	void convertComponentToGlobalCoords(const Point3f& component, Point3f& global);


	/**
	 * Converts the current position of this component to its parent's
	 * coordinate frame (if it has a parent).
	 *
	 * @param parentX the x-coordinate in the parent frame
	 * @param parentY the y-coordinate in the parent frame
	 */
	void convertPositionToParentCoords(double& parentX, double& parentY);

	// CURRENT STATE MANIPULATION

	/**
	 * Moves this component by the given values.
	 *
	 * @param d the values to move this component by.
	 */
	inline void moveBy(const Point3f& d) { currentState.position += d; }

	/**
	 * Moves this component by the given values. If only one argument is given,
	 * the component is moved only along the x-coordinate. If two arguments are
	 * given, the component is moved along the x- and y-coordinates. If all
	 * three are given, the component is moved along all three coordinates by
	 * the corresponding values.
	 *
	 * @param dx the value to move this component by in the x-coordinate.
	 * @param dy the value to move this component by in the y-coordinate.
	 * @param dz the value to move this component by in the z-coordinate.
	 */
	inline void moveBy(float dx, float dy = 0, float dz = 0) {
		currentState.position.x += dx; currentState.position.y += dy;
		currentState.position.z += dz;
	}

	/**
	 * Moves this component and the composite branch under it by the given values.
	 *
	 * @param d the values to move this component branch by.
	 */
	void moveBranchBy(const Point3f& d);

	/**
	 * Moves this component and the composite branch under it by the given values.
	 *
	 * @param dx the value to move this component by in the x-coordinate.
	 * @param dy the value to move this component by in the y-coordinate.
	 * @param dz the value to move this component by in the z-coordinate.
	 */
	void moveBranchBy(float dx, float dy = 0, float dz = 0);

	/**
	 * Rotates this component in the x-y plane by the given angle in radians.
	 *
	 * @param angleRadians the angle to rotate this component by.
	 */
	inline void rotate(double angleRadians) { currentState.rotationAngle += angleRadians; }

	/**
	 * Rotates the branch of this component in the x-y plane by the given angle
	 * in radians.
	 *
	 * @param angleRadians the angle to rotate this component by.
	 */
	void rotateBranch(double angleRadians);

	// STATE STACK MANAGEMENT

	/**
	 * Saves the current state of this component by pushing it to the state stack.
	 */
	inline void saveCurrentState() { stateStack.push(currentState); }

	/**
	 * Retrieves the state at the top of the state stack and sets it as the
	 * current state of this component.
	 */
	inline void retrieveState() { currentState = stateStack.top(); stateStack.pop(); }

	/**
	 * Retrieves the state at the top of the state stack and sets it as the
	 * current state of this component, keeping the attributes determined by
	 * the invariants flag.
	 *
	 * @param invariants the OR-combination of the identifiers of the
	 * attributes that should be kept (i.e., not retrieved).
	 */
	void retrieveState(unsigned int invariants);

	/**
	 * Returns the state currently at the top of state stack.
	 *
	 * @return the state currently at the top of state stack.
	 */
	inline VisComponentState obtainTopState() { return stateStack.top(); }

	/**
	 * Discards the state currently at the top of the state stack.
	 */
	inline void discardTopState() { stateStack.pop(); }

	/**
	 * Returns true if the state stack of this component is empty.
	 *
	 * @return true if the state stack of this component is empty.
	 */
	inline bool isStateStackEmpty() { return stateStack.empty(); }

	// COLOR-ID CONVERSIONS

	/**
	 * Returns the conversion to RGB values of the given id.
	 *
	 * @param id the id to be converted.
	 * @param color the returned RGB color corresponding to the given id.
	 */
	static void convertIdToColor(unsigned long id, unsigned char* color);

	/**
	 * Returns the id resulting from the conversion of the given color.
	 *
	 * @param color the color to be converted.
	 * @return the id value corresponding to the given color.
	 */
	static unsigned long convertColorToId(unsigned char *color);

	// COMPOSITE COMPLEMENTS

	/*
	 * Removes a child of this component by its id (it uses sequential search).
	 * If no child is found with the given id, nothing is done.
	 *
	 * @param childId the identifier of the child to be removed.
	 */
//	void removeChild(unsigned long childId);

	// I-BUFFERS

	/**
	 * Adds an active i-buffer to this component. The insertion order
	 * defines the sequential identifier to access the property (starting at
	 * zero). If a property is deleted from this component, all the identifiers
	 * have to be shifted.
	 *
	 * @param buffer the active i-buffer to be added to this component.
	 */
	inline void addActiveBuffer(IBufferProxy* buffer) {
		buffer->setOwner(this); activeBuffers.push_back(buffer);
	}

	/**
	 * Adds a passive i-buffer to this component. The insertion order defines
	 * the sequential identifier to access the property (starting at zero). If
	 * a property is deleted from this component, all the identifiers have to
	 * be shifted.
	 *
	 * @param buffer the passive i-buffer to be added to this component.
	 */
	inline void addPassiveBuffer(IBufferProxy* buffer) { passiveBuffers.push_back(buffer); }

	/**
	 * Returns the number of active buffers currently in this component.
	 *
	 * @return the number of active buffers currently in this component.
	 */
	inline unsigned int getNumberActiveBuffers() { return (unsigned int) activeBuffers.size(); }

	/**
	 * Returns the number of passive buffers currently in this component.
	 *
	 * @return the number of passive buffers currently in this component.
	 */
	inline unsigned int getNumberPassiveBuffers() { return (unsigned int) passiveBuffers.size(); }

	/**
	 * Updates the passive buffers by searching in the path from this component
	 * parent to the root of the composite structure for buffers of the same
	 * type as specified in this component's passive buffer list. The first
	 * buffer found is associated as the respective passive buffer of this
	 * component for a given property.
	 */
	void updatePassiveBuffers();

	/**
	 * Recursively updates the passive buffers of the branch below this
	 * component node by searching in the path from this component parent to
	 * the root of the composite structure for buffers of the same type as
	 * specified in the component's passive buffer list. The first buffer found
	 * is associated as the respective passive buffer of the specific component
	 * for a given property.
	 */
	void updateBranchPassiveBuffers();

	/**
	 * Resizes all the active buffers of this component. The buffers are set to
	 * have the same dimensions as the component's width and height. The
	 * virtual dimensions are set with the same values as the actual
	 * dimensions.
	 */
	void resizeActiveBuffers();

	/**
	 * Resizes all the active buffers of this component and the components
	 * below it in the composition tree. The buffers are set to have the same
	 * dimensions as the component's width and height. The virtual dimensions
	 * are set with the same values as the actual dimensions.
	 */
	void resizeBranchActiveBuffers();

	/**
	 * Returns the amount of memory allocated by the active buffers of this
	 * component in KyloBytes.
	 *
	 * @return the amount of memory allocated by the active buffers of this
	 * component in KyloBytes.
	 */
	unsigned long getActiveBuffersMemorySizeKBytes();

	// STRATEGY

	/**
	 * Adds a strategy to the ones associated with this component by pushing it
	 * at the front of the strategy chain. Therefore, it will be called *after*
	 * the strategies that are already in the chain.
	 *
	 * @param str a VisComponentStrategy to be added to this component.
	 */
	void pushStrategy(VisComponentStrategy* str);

	/**
	 * Returns true if this component has a strategy of the class T in the
	 * strategy decorator chain.
	 *
	 * @return true if this component has a strategy of the class T in the
	 * strategy decorator chain, false otherwise.
	 */
	template<class T> bool hasStrategy() {
		VisComponentStrategy* str = strategy;
		while (str) {
			// Checking if the current strategy is of the given type
			if (isTypeOf<T, VisComponentStrategy>(str)) return true;
			else str = str->getNextStrategy(); // Checking the next strategy
		}
		// Only gets here if no strategy of the given type is found
		return false;
	}
	

	/**
	 * Returns the reference to the specified subclass of VisComponentStrategy
	 * associated with this component. If this component does not have such a
	 * strategy, NULL is returned.
	 *
	 * @return the reference to the specified strategy instance.
	 */
	template<class T> T* getStrategy() {
		VisComponentStrategy* str = strategy;
		while (str) {
			// Checking if the current strategy is of the given type
			if (isTypeOf<T, VisComponentStrategy>(str)) return (T*) str;
			else str = str->getNextStrategy(); // Checking the next strategy
		}
		// Only gets here if no strategy of the given type is found
		return NULL;
	}
	

	/**
	 * Removes the first occurrance of the strategy of the given type from the
	 * sequence of strategies in this component. It returns true if the
	 * strategy is successfully removed, and false is no strategy of the
	 * specified class can be found.
	 *
	 * @return true if the removal was successful and false otherwise.
	 */
	template<class T> bool removeStrategy() {
		VisComponentStrategy* current = strategy;
		VisComponentStrategy* previous = NULL;
		while (current) {
			// Checking if the current strategy is of the given type
			if (isTypeOf<T, VisComponentStrategy>(current)) {
				// Checking of there is a previous strategy
				if (previous) {
					// Updating the reference of the previous strategy to the next
					previous->setNextStrategy(current->getNextStrategy());
				} else {
					// We are in the beginning of the sequence, get the second strategy
					previous = current->getNextStrategy();
					// Updating the first strategy in the sequence
					strategy = previous;
				}
				// Removing the current strategy
				delete current;
				return true;
			} else {
				// Going for the next strategy
				previous = current;
				current = current->getNextStrategy();
			}
		}
		// Only gets here if no strategy of the given type is found
		return false;
	}
	

	/**
	 * Destroys the last strategy in the startegy chain of this component.
	 */
	void destroyLastStrategy();
	

	/**
	 * Destroys all the strategies in this component's strategy chain.
	 */
	void destroyAllStrategies();

	// MISCELLANEOUS

	/**
	 * Returns true if the given global coordinates are inside the bounding
	 * rectangle of this component (given by its widht, height, and
	 * position/center). Returns false, otherwise.
	 *
	 * @return true if the given global coordinates are inside this component.
	 */
	bool isInside(unsigned int x, unsigned int y);
	
	
	// ACCESSOR METHODS

	/**
	 * Returns the unique identifier of this component.
	 *
	 * @return the unique identifier of this component.
	 */
	inline unsigned long getId() { return id; }
	

	/**
	 * Sets the unique identifier of this component. It also sets the id color
	 * of this component in accord with the set id.
	 *
	 * @param newId the unique identifier of this component.
	 */
	inline void setId(unsigned long newId) { 
		id = newId; 
		unsigned char c[3] = { 0, 0, 0 };
		convertIdToColor(id, c); setIdColor(c);
	}
	

	/**
	 * Returns the color corresponding to the identifier of this component in
	 * the given parameter.
	 *
	 * @param color the color corresponding to the identifier of this component.
	 */
	inline void getIdColor(unsigned char *color) {
		color[0] = idColor[0]; color[1] = idColor[1]; color[2] = idColor[2];
	}
	

	/**
	 * Sets the color corresponding to the identifier of this component.
	 *
	 * @param colorId the color corresponding to the identifier of this component.
	 */
	inline void setIdColor(unsigned char *colorId) {
		idColor[0] = colorId[0]; idColor[1] = colorId[1]; idColor[2] = colorId[2];
	}
	

	/**
	 * Returns a pointer to the manager of this component.
	 *
	 * @return a pointer to the manager of this component.
	 */
	inline LargeDisplayManager* getManager() { return manager; }
	

	/**
	 * Sets the pointer to the manager of this component.
	 *
	 * @param m the pointer to the manager to be set for this component.
	 */
	inline void setManager(LargeDisplayManager* m) { manager = m; }
	
	// ANIMATION

	/**
	 * Returns a copy of the current state object of this component.
	 *
	 * @return a copy of the current state object of this component.
	 */
	inline VisComponentState getCurrentState() { return currentState; }
	

	/**
	 * Sets the current state object of this component.
	 *
	 * @param state the state object to be set as current.
	 */
	inline void setCurrentState(VisComponentState state) { currentState = state; }
	

	/**
	 * Returns the value used for the animation linear step.
	 *
	 * @return the value of the animation linear step.
	 */
	inline float getAnimationStep() { return animationStep; }
	

	/**
	 * Sets the linear step used for animation.
	 *
	 * @param step the value of the animation linear step
	 */
	inline void setAnimationStep(float step) { animationStep = step; }
	

	/**
	 * Returns the current value of the animation parameter.
	 *
	 * @return the current value of the animation parameter.
	 */
	inline float getAnimationParameter() { return animationParameter; }
	

	/**
	 * Sets the current value of the animation parameter.
	 *
	 * @param value the value of the animation parameter.
	 */
	inline void setAnimationParameter(float value) { animationParameter = value; }
	

	/**
	 * Returns true if an animation is running.
	 *
	 * @return true if an animation is running.
	 */
	inline bool isAnimating() { return animating; }
	

	/**
	 * Sets the animation flag of this component (can be used to prevent buffer
	 * reading while animating is true).
	 *
	 * @param value the value to be set to the animating flag.
	 */
	inline void setAnimating(bool value) { animating = value; }
	

	/**
	 * Returns the current source state for the animation of this component.
	 *
	 * @return the current source state for the animation of this component.
	 */
	inline VisComponentState getSourceState() { return sourceState; }
	

	/**
	 * Sets the current source state for the animation of this component.
	 *
	 * @param state the state to be made the source of this component animation.
	 */
	inline void setSourceState(VisComponentState state) { sourceState = state; }
	

	/**
	 * Returns the current target state for the animation of this component.
	 *
	 * @return the current target state for the animation of this component.
	 */
	inline VisComponentState getTargetState() { return targetState; }
	

	/**
	 * Sets the current target state for the animation of this component.
	 *
	 * @param state the state to be made the target of this component animation.
	 */
	inline void setTargetState(VisComponentState state) { targetState = state; }
	

	/**
	 * Returns the current invariants for the animation triggered when this
	 * component is removed from a container.
	 *
	 * @return the current invariants for removing animation.
	 */
	inline unsigned int getRemovingInvariants() { return removingInvariants; }
	

	/**
	 * Sets the current invariants for the animation triggered when this
	 * component is removed from a container.
	 *
	 * @param invariants the current invariants for removing animation.
	 */
	inline void setRemovingInvariants(unsigned int invariants) { removingInvariants = invariants; }
	
	// I-BUFFERS

	/**
	 * Returns the active i-buffer proxy object used to represent the specified
	 * property. If there is no buffer for the given id, NULL is returned.
	 *
	 * @param propId the identifier of the property represented in the buffer.
	 * @return the IBufferProxy object that represents the specified property.
	 */
	inline IBufferProxy* getActiveBuffer(unsigned int propId) {
		if (propId >= activeBuffers.size()) return NULL; return activeBuffers[propId];
	}

	/**
	 * Sets the given IBuffer object as an active buffer associated with the
	 * specified property index. If there is no buffer for the given id,
	 * nothing is done.
	 *
	 * @param propId the identifier of the property being set.
	 * @param buffer the IBufferProxy object representing this property.
	 */
	inline void setActiveBuffer(unsigned int propId, IBufferProxy* buffer) {
		if (propId < activeBuffers.size()) activeBuffers[propId] = buffer;
	}

	/**
	 * Returns an IBufferProxy object from this component's active buffer list
	 * that have the same type as specified. If no buffer of the given type are
	 * found, NULL is returned.
	 *
	 * @param t the type of buffer to be returned.
	 * @return an active buffer of the given type or NULL if none is available.
	 */
	IBufferProxy* getActiveBufferByType(unsigned int t);

	/**
	 * Returns the passive i-buffer proxy object used to represent the specified
	 * property. If there is no buffer for the given id, NULL is returned.
	 *
	 * @param propId the identifier of the property represented in the buffer.
	 * @return the IBufferProxy object that represents the specified property.
	 */
	inline IBufferProxy* getPassiveBuffer(unsigned int propId) {
		if (propId >= passiveBuffers.size()) return NULL; 
		return passiveBuffers[propId];
	}

	/**
	 * Returns an IBufferProxy object from this component's passive buffer list
	 * that have the same type as specified. If no buffer of the given type are
	 * found, NULL is returned.
	 *
	 * @param t the type of buffer to be returned.
	 * @return an passive buffer of the given type or NULL if none is available.
	 */
	IBufferProxy* getPassiveBufferByType(unsigned int t);

	/**
	 * Sets the given IBuffer object as a passive buffer associated with the
	 * specified property index. If there is no buffer for the given id,
	 * nothing is done.
	 *
	 * @param propId the identifier of the property being set.
	 * @param buffer the IBufferProxy object representing this property.
	 */
	inline void setPassiveBuffer(unsigned int propId, IBufferProxy* buffer) {
		if (propId < activeBuffers.size()) passiveBuffers[propId] = buffer;
	}
	
	// STRATEGY

	/**
	 * Returns the VisComponentStrategy object being used by this component.
	 *
	 * @return the VisComponentStrategy object being used by this component.
	 */
	inline VisComponentStrategy* getStrategy() { return strategy; }


	/**
	 * Sets the VisComponentStrategy to be used by this component.
	 *
	 * @param str the VisComponentStrategy object to be used by this component.
	 */
	inline void setStrategy(VisComponentStrategy* str) {
		strategy = str; strategy->setComponent(this); /*strategy->initPropertiesComponent();*/
	}

	// CURRENT STATE

	/**
	 * Returns the position of the current state of this component.
	 *
	 * @return the position of the current state of this component.
	 */
	inline const Point3f& getPosition() { return currentState.position; }


	/**
	 * Sets the position of the current state of this component.
	 * @param pos the position to be set to the current state of this component.
	 */
	inline void setPosition(const Point3f& pos) { currentState.position = pos; }

	/**
	 * Sets the position of the current state of this component.
	 *
	 * @param x the x-coordinate of the position to be set to the current state of
	 * this component.
	 * @param y the y-coordinate of the position to be set to the current state of
	 * this component.
	 */
	inline void setPosition(float x, float y) {
		currentState.position.x = x; currentState.position.y = y; }

	/**
	 * Sets the position of the current state of this component.
	 *
	 * @param x the x-coordinate of the position to be set to the current state
	 * of this component.
	 * @param y the y-coordinate of the position to be set to the current state
	 * of this component.
	 * @param z the z-coordinate of the position to be set to the current state
	 * of this component.
	 */
	inline void setPosition(float x, float y, float z) {
		currentState.position = Point3f(x, y, z); }

	/**
	 * Returns the rotation angle in radians of the current state of this
	 * component.
	 *
	 * @return the rotation angle in radians of the current state of this
	 * component.
	 */
	inline double getRotationAngle() { return currentState.rotationAngle; }

	/**
	 * Sets the rotation angle in radians of the current state of this
	 * component.
	 *
	 * @param angle the rotation angle in radians to be set to the current
	 * state of this component.
	 */
	inline void setRotationAngle(double angle) { currentState.rotationAngle = angle; }

	/**
	 * Returns the width of the current state of this component.
	 *
	 * @return the width of the current state of this component.
	 */
	inline unsigned int getWidth() { return currentState.width; }

	/**
	 * Sets the width of the current state of this component.
	 *
	 * @param w the width to be set to the current state of this component.
	 */
	inline void setWidth(unsigned int w) { currentState.width = w; }

	/**
	 * Returns the height of the current state of this component.
	 *
	 * @return the height of the current state of this component.
	 */
	inline unsigned int getHeight() { return currentState.height; }

	/**
	 * Sets the height of the current state of this component.
	 *
	 * @param h the height to be set to the current state of this component.
	 */
	inline void setHeight(unsigned int h) { currentState.height = h; }

	/**
	 * Returns the scale factor along the x-coordinate of the current state of
	 * this component.
	 *
	 * @return the scale factor along the x-coordinate of the current state of
	 * this component.
	 */
	inline float getScaleFactorX() { return currentState.scaleFactorX; }

	/**
	 * Returns the scale factor along the y-coordinate of the current state of
	 * this component.
	 *
	 * @return the scale factor along the y-coordinate of the current state of
	 * this component.
	 */
	inline float getScaleFactorY() { return currentState.scaleFactorY; }

	/**
	 * Returns the scale factor along the z-coordinate of the current state of
	 * this component.
	 *
	 * @return the scale factor along the z-coordinate of the current state of
	 * this component.
	 */
	inline float getScaleFactorZ() { return currentState.scaleFactorZ; }

	/**
	 * Sets the scale factor of the current state of this component uniformly
	 * (i. e., equal in all coordinates).
	 *
	 * @param h the uniform scale factor to be set to the current state of this
	 * component.
	 */
	inline void setScaleFactor(float s) {
		currentState.scaleFactorX = s;
		currentState.scaleFactorY = s;
		currentState.scaleFactorZ = s;
	}

	/**
	 * Sets the scale factor along the x-coordinate of the current state of
	 * this component.
	 *
	 * @param h the x-coordinate scale factor to be set to the current state of
	 * this component.
	 */
	inline void setScaleFactorX(float s) { currentState.scaleFactorX = s; }

	/**
	 * Sets the scale factor along the y-coordinate of the current state of
	 * this component.
	 *
	 * @param h the y-coordinate scale factor to be set to the current state of
	 * this component.
	 */
	inline void setScaleFactorY(float s) { currentState.scaleFactorY = s; }

	/**
	 * Sets the scale factor along the z-coordinate of the current state of
	 * this component.
	 *
	 * @param h the z-coordinate scale factor to be set to the current state of
	 * this component.
	 */
	inline void setScaleFactorZ(float s) { currentState.scaleFactorZ = s; }

	/**
	 * Returns the RGBA color of the current state of this component.
	 *
	 * @return the RGBA color of the current state of this component.
	 */
	inline float* getColor() { return currentState.color; }

	/**
	 * Sets the RGBA color of the current state of this component.
	 *
	 * @param c the RGBA color of the current state of this component.
	 */
	inline void setColor(float* c) {
		currentState.color[0] = c[0]; currentState.color[1] = c[1];
		currentState.color[2] = c[2]; currentState.color[3] = c[3];
	}

	/**
	 * Sets the RGBA color of the current state of this component.
	 *
	 * @param r the red component of the color of the current state of this
	 * component.
	 * @param g the green component of the color of the current state of this
	 * component.
	 * @param b the blue component of the color of the current state of this
	 * component.
	 * @param a the alpha component of the color of the current state of this
	 * component.
	 */
	inline void setColor(float r, float g, float b, float a = 1.0) {
		currentState.color[0] = r; currentState.color[1] = g;
		currentState.color[2] = b; currentState.color[3] = a;
	}

	/**
	 * Returns the alpha component of the RGBA color of the current state of
	 * this component.
	 *
	 * @return the alpha component of the RGBA color of the current state of
	 * this component.
	 */
	inline float getAlpha() { return currentState.color[3]; }

	/**
	 * Sets the alpha component of the RGBA color of the current state of this
	 * component.
	 *
	 * @param a the alpha component of the RGBA color of the current state of
	 * this component.
	 */
	inline void setAlpha(float a) { currentState.color[3] = a; }


	// BUFFER ACCESS TEMPLATE METHODS

	/**
	 * Sets the parameter value with the value in the specified passive buffer
	 * at the given global coordinates. Returns 0 if successful or 1 if the
	 * buffer is not found or the given global coordinates fall out of the
	 * buffer range.
	 *
	 * @param bufferType the constant that identifies the type of the buffer.
	 * @param x the global x-coordinate of the position of the buffer access.
	 * @param y the global y-coordinate of the position of the buffer access.
	 * @param value the variable where the obtianed result is put.
	 * @param T the data type in the specified buffer.
	 * @return 0 if successful, 1 otherwise.
	 */
	template<class T>
	int getActiveBufferValue(unsigned int bufferType, unsigned int x, unsigned int y, T& value) {
		// Getting the button identifier from the active buffer
		IBufferProxy* bufferProxy = getActiveBufferByType(bufferType);
		if (bufferProxy && bufferProxy->getBuffer()) {
			// Getting the buffer
			IBuffer<T>* buffer = (IBuffer<T>*) bufferProxy->getBuffer();
			if (buffer) {
				// Calculating the buffer position
				double bufferX = 0, bufferY = 0;
				convertGlobalToBufferCoords(x, y, bufferX, bufferY);
				// Checking if the buffer coords are valid
				if (buffer->isInsideActualBuffer(bufferX, bufferY)) {
					// Comparing the buffer hit with the resizing value
					value = buffer->getValue((unsigned int) bufferX, (unsigned int) bufferY);
					return 0;
				}
			}
		}
		/*throw std::exception(
			"Value could not be obtained. A buffer of this type is not available or the indices are out of its range.");*/
		return 1;
	}

	/**
	 * Fills the array value with the value in the specified active buffer at
	 * the given global coordinates. Returns 0 if successful or 1 if the buffer
	 * is not found or the given global coordinates fall out of the buffer
	 * range, a std::exception is.
	 *
	 * @param bufferType the constant that identifies the type of the buffer.
	 * @param x the global x-coordinate of the position of the buffer access.
	 * @param y the global y-coordinate of the position of the buffer access.
	 * @param value the variable where the obtianed result is put.
	 * @param T the data type in the specified buffer.
	 * @return 0 if successful, 1 otherwise.
	 */
	template<class T>
	int getActiveBufferValue(unsigned int bufferType, unsigned int x, unsigned int y, T* value) {
		// Getting the button identifier from the active buffer
		IBufferProxy* bufferProxy = getActiveBufferByType(bufferType);
		if (bufferProxy && bufferProxy->getBuffer()) {
			// Getting the buffer
			IBuffer<T>* buffer = (IBuffer<T>*) bufferProxy->getBuffer();
			if (buffer) {
				// Calculating the buffer position
				double bufferX = 0, bufferY = 0;
				convertGlobalToBufferCoords(x, y, bufferX, bufferY);
				// Checking if the buffer coords are valid
				if (buffer->isInsideActualBuffer(bufferX, bufferY)) {
					// Comparing the buffer hit with the resizing value
					buffer->getValue((unsigned int) bufferX, (unsigned int) bufferY, value);
					return 0;
				}
			}
		}
		/*throw std::exception(
			"Value could not be obtained. A buffer of this type is not available or the indices are out of its range.");*/
		return 1;
	}

	/**
	 * Sets the parameter value with the value in the specified passive buffer
	 * at the given global coordinates. Returns 0 if successful or 1 if the
	 * buffer is not found or the given global coordinates fall out of the
	 * buffer range.
	 *
	 * @param bufferType the constant that identifies the type of the buffer.
	 * @param x the global x-coordinate of the position of the buffer access.
	 * @param y the global y-coordinate of the position of the buffer access.
	 * @param value the variable where the obtianed result is put.
	 * @param T the data type in the specified buffer.
	 * @return 0 if successful, 1 otherwise.
	 */
	template<class T>
	int getPassiveBufferValue(unsigned int bufferType, float x, float y, T& value) {
		// Getting the button identifier from the active buffer
		IBufferProxy* bufferProxy = getPassiveBufferByType(bufferType);
		if (bufferProxy && bufferProxy->getBuffer()) {
			// Getting the buffer
			IBuffer<T>* buffer = (IBuffer<T>*) bufferProxy->getBuffer();
			if (buffer) {
				// Calculating the buffer position
				double bufferX = 0, bufferY = 0;
				bufferProxy->getOwner()->convertGlobalToBufferCoords(x, y, bufferX, bufferY);
				// Checking if the buffer coords are valid
				if (buffer->isInsideActualBuffer(bufferX, bufferY)) {
					// Comparing the buffer hit with the resizing value
					value = buffer->getValue((unsigned int) bufferX, (unsigned int) bufferY);
					return 0;
				}
			}
		}
		/*throw std::exception(
			"Value could not be obtained. A buffer of this type is not available or the indices are out of its range.");*/
		return 1;
	}

	/**
	 * Fills the array value with the value in the specified passive buffer at
	 * the given global coordinates. Returns 0 if successful or 1 if the buffer
	 * is not found or the given global coordinates fall out of the buffer
	 * range.
	 *
	 * @param bufferType the constant that identifies the type of the buffer.
	 * @param x the global x-coordinate of the position of the buffer access.
	 * @param y the global y-coordinate of the position of the buffer access.
	 * @param value the variable where the obtianed result is put.
	 * @param T the data type in the specified buffer.
	 * @return 0 if successful, 1 otherwise.
	 */
	template<class T>
	int getPassiveBufferValue(unsigned int bufferType, unsigned int x, unsigned int y, T* value) {
		// Getting the button identifier from the active buffer
		IBufferProxy* bufferProxy = getPassiveBufferByType(bufferType);
		if (bufferProxy) {// && bufferProxy->getBuffer()) {
			// Getting the buffer
			IBuffer<T>* buffer = (IBuffer<T>*) bufferProxy->getBuffer();
			if (buffer) {
				// Calculating the buffer position
				double bufferX = 0, bufferY = 0;
				bufferProxy->getOwner()->convertGlobalToBufferCoords(x, y, bufferX, bufferY);
				// Checking if the buffer coords are valid
				if (buffer->isInsideActualBuffer(bufferX, bufferY)) {
					// Comparing the buffer hit with the resizing value
					buffer->getValue((unsigned int) bufferX, (unsigned int) bufferY, value);
					return 0;
				}
			}
		}
		//return (T) BufferConstants::NO_BUTTON;
		//throw std::exception(
		//	"Value could not be obtained. A buffer of this type is not available or the indices are out of its range.");
		return 1;
	}


	// DEBUGGING

	/**
	 * Prints the data in this component for debugging purposes.
	 */
	void print();

	/**
	 * Prints the children of this component for debugging purposes.
	 */
	void printChildren();


protected:

	/**
	 * Executes the subclass specified code before rendering this component.
	 */
	inline virtual void preRender() {}

	/**
	 * Executes the subclass specified code after rendering this component.
	 */
	inline virtual void postRender() {}
	
};

#endif // VISCOMPONENT_H
